home *** CD-ROM | disk | FTP | other *** search
/ Hot Super Models / Hot Super Models.iso / unix / x11 / xv200.tar / xv-2.00 / xvpopup.c < prev    next >
C/C++ Source or Header  |  1992-01-02  |  11KB  |  425 lines

  1. /* 
  2.  * xvpopup.c - popup "Are you sure?  Yes/No/Maybe" sort of dialog box
  3.  *
  4.  * callable functions:
  5.  *
  6.  *   CenterMapWindow(win,x,y)  -  maps and centers a window around the mouse
  7.  *   PopUp(str,...)        -  maps, sets up popW
  8.  *   OpenAlert(str)        -  maps a button-less window
  9.  *   CloseAlert()          -  closes a button-less window
  10.  *   PUCheckEvent(event)   -  called by event handler
  11.  *   TextRect()            -  draws semi-complex strings in a rectangle
  12.  */
  13.  
  14. /*
  15.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  16.  *                       The University of Pennsylvania
  17.  *
  18.  * Permission to use, copy, and distribute for non-commercial purposes,
  19.  * is hereby granted without fee, providing that the above copyright
  20.  * notice appear in all copies and that both the copyright notice and this
  21.  * permission notice appear in supporting documentation.
  22.  *
  23.  * The software may be modified for your own purposes, but modified versions
  24.  * may not be distributed.
  25.  *
  26.  * This software is provided "as is" without any expressed or implied warranty.
  27.  *
  28.  * The author may be contacted via:
  29.  *    US Mail:   John Bradley
  30.  *               GRASP Lab, Room 301C
  31.  *               3401 Walnut St.
  32.  *               Philadelphia, PA  19104
  33.  *
  34.  *    Phone:     (215) 898-8813
  35.  *    EMail:     bradley@cis.upenn.edu
  36.  */
  37.  
  38. #include "xv.h"
  39. #include "bitmaps.h"
  40.  
  41. #define PUWIDE 400
  42. #define PUHIGH 170
  43. #define BUTTH 24
  44.  
  45.  
  46. #ifdef __STDC__
  47. static void createPUD(void);
  48. static void drawPUD(int, int, int, int);
  49. static void clickPUD(int, int);
  50. #else
  51. static void createPUD(), drawPUD(), clickPUD();
  52. #endif
  53.  
  54.  
  55. /* local variables */
  56. Window popW;
  57. int    nbts, selected, popUp=0, firsttime=1;
  58. BUTT  *bts;
  59. char  *text;
  60. char   accel[8];
  61.  
  62.  
  63. /***************************************************/
  64. void CenterMapWindow(win, dx, dy, w, h)
  65.      Window win;
  66.      int    dx, dy, w, h;
  67. {
  68.   XSizeHints hints;
  69.   Window       rW,cW;
  70.   int          rx,ry,x,y,wx,wy;
  71.   unsigned int mask;
  72.  
  73.  
  74.   if (!XQueryPointer(theDisp,rootW,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  75.     /* couldn't query mouse.  just center on screen */
  76.     wx = (dispWIDE-w)/2;   wy = (dispHIGH-h)/2;
  77.   }
  78.   else {
  79.     wx = x - dx;
  80.     wy = y - dy;
  81.     if (wx<0) wx = 0;
  82.     if (wy<0) wy = 0;
  83.     if (wx + w > dispWIDE) wx = dispWIDE - w;
  84.     if (wy + h > dispHIGH) wy = dispHIGH - h;
  85.   }
  86.  
  87.   wx -= (p_offx + ch_offx);
  88.   wy -= (p_offy + ch_offy);
  89.  
  90.   if (!XGetNormalHints(theDisp, win, &hints)) hints.flags = 0;
  91.   hints.width  = hints.min_width  = hints.max_width  = w;
  92.   hints.height = hints.min_height = hints.max_height = h;
  93.   hints.x = wx;  hints.y = wy;
  94.   hints.flags  |= (USSize | PMinSize | PMaxSize | USPosition);
  95.   XSetNormalHints(theDisp, win, &hints);
  96.  
  97.   XMoveWindow(theDisp, win, wx, wy);
  98.   XMapRaised(theDisp, win);
  99. }
  100.  
  101.  
  102. /***************************************************/
  103. int PopUp(txt, labels, n)
  104.      char *txt, *labels[];
  105.      int   n;
  106. {
  107.   int    i;
  108.   XEvent event;
  109.  
  110.  
  111.   if (firsttime) createPUD();
  112.  
  113.   XStoreName(theDisp, popW, "xv confirm");
  114.   XSetIconName(theDisp, popW, "xv confirm");
  115.  
  116.   bts = (BUTT *) malloc(n * sizeof(BUTT));
  117.   if (!bts) FatalError("unable to malloc buttons in popup\n");
  118.   nbts = n;
  119.   selected = 0;
  120.   text = txt;
  121.  
  122.   for (i=0; i<n; i++) {
  123.     BTCreate(&bts[i], popW, PUWIDE - (n-i) * (80 + 10), PUHIGH - 10 - BUTTH,
  124.          80, BUTTH, labels[i]+1, infofg, infobg);
  125.     accel[i] = labels[i][0];
  126.   }
  127.  
  128.   /* center last button in window around mouse position, with constraint that 
  129.      window be fully on the screen */
  130.  
  131.   CenterMapWindow(popW, 40 + bts[nbts-1].x, BUTTH/2 + bts[nbts-1].y,
  132.           PUWIDE, PUHIGH);
  133.   popUp = 1;
  134.  
  135.   /* MUST wait for VisibilityNotify event to come in, else we run the risk
  136.      of UnMapping the window *before* the Map request completed.  This 
  137.      appears to be bad, (It leaves an empty window frame up.) though it
  138.      generally only happens on slow servers.  Better safe than screwed... */
  139.  
  140.   XWindowEvent(theDisp, popW, VisibilityChangeMask, &event);
  141.  
  142.   /* block until this window gets closed */
  143.   while (popUp) {
  144.     XNextEvent(theDisp, &event);
  145.     HandleEvent(&event, &i);
  146.   }
  147.  
  148.   /* free stuff */
  149.   XUnmapWindow(theDisp, popW);
  150.   free(bts);
  151.  
  152.   return(selected);
  153. }
  154.  
  155.  
  156. /***************************************************/
  157. void OpenAlert(txt)
  158.      char *txt;
  159. {
  160.   /* pops up a window with txt displayed in it (*no buttons*).  
  161.      returns immediately.  window is close by 'CloseAlert()'.
  162.      No 'PopUp()' calls are allowed while an Alert is displayed. */
  163.  
  164.   int    i;
  165.   XEvent event;
  166.  
  167.  
  168.   if (firsttime) createPUD();
  169.  
  170.   XStoreName(theDisp, popW, "xv notice");
  171.   XSetIconName(theDisp, popW, "xv notice");
  172.  
  173.   nbts = 0;
  174.   selected = 0;
  175.   text = txt;
  176.  
  177.   /* center last button in window around mouse position, with constraint that 
  178.      window be fully on the screen */
  179.  
  180.   CenterMapWindow(popW, PUWIDE/2, PUHIGH/2, PUWIDE, PUHIGH);
  181.   popUp = 1;
  182.  
  183.   /* MUST wait for VisibilityNotify event to come in, else we run the risk
  184.      of UnMapping the window *before* the Map request completed.  This 
  185.      appears to be bad, (It leaves an empty window frame up.) though it
  186.      generally only happens on slow servers.  Better safe than screwed... */
  187.  
  188.   XWindowEvent(theDisp, popW, VisibilityChangeMask, &event);
  189.   drawPUD(0, 0, PUWIDE, PUHIGH);
  190.   XFlush(theDisp);
  191. }
  192.  
  193.  
  194. /***************************************************/
  195. void CloseAlert()
  196. {
  197.   popUp = 0;
  198.   XUnmapWindow(theDisp, popW);
  199. }
  200.  
  201.  
  202. /***************************************************/
  203. int PUCheckEvent(xev)
  204. XEvent *xev;
  205. {
  206.   /* check event to see if it's for us.  If so, return 1, otherwise 0 */
  207.  
  208.   int rv = 0;
  209.  
  210.   if (!popUp) return(0);
  211.  
  212.   if (xev->type == Expose) {
  213.     XExposeEvent *e = (XExposeEvent *) xev;
  214.     if (e->window == popW) {
  215.       drawPUD(e->x, e->y, e->width, e->height);
  216.       rv = 1;
  217.     }
  218.   }
  219.  
  220.   else if (xev->type == ButtonPress) {
  221.     XButtonEvent *e = (XButtonEvent *) xev;
  222.  
  223.     if (e->button == Button1 && e->window == popW) {
  224.       clickPUD(e->x,e->y);
  225.       rv = 1;
  226.     }
  227.   }
  228.  
  229.  
  230.   else if (xev->type == KeyPress) {
  231.     XKeyEvent *e = (XKeyEvent *) xev;
  232.     char buf[128];  KeySym ks;  XComposeStatus status;  
  233.     int stlen, i;
  234.     
  235.     stlen = XLookupString(e,buf,128,&ks,&status);
  236.     buf[stlen] = '\0';
  237.  
  238.     /* note: we accept keyboard accellerators in *any* window */
  239.     if (stlen) {
  240.       if (buf[0] == '\r') buf[0] = '\n';
  241.  
  242.       /* search for character in accel table */
  243.       for (i=0; i<nbts; i++) {
  244.     if (buf[0] == accel[i] && buf[0] != ' ') {
  245.       FakeButtonPress(&bts[i]);
  246.       rv = 1;
  247.     }
  248.       }
  249.  
  250.       if (!rv && buf[0]=='\033' && nbts==1) { /* ESC accepted in 1-but pu's */
  251.     FakeButtonPress(&bts[0]);
  252.     rv = 1;
  253.       }
  254.     }
  255.     else rv = 1;    /* 'accept' non-char strings (ie, shift or ctrl press) */
  256.   }
  257.  
  258.   else if (xev->type == ClientMessage) {
  259.     Atom proto, delwin;
  260.     XClientMessageEvent *client_event = (XClientMessageEvent *) xev;
  261.  
  262.     proto  = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
  263.     delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
  264.  
  265.     if (client_event->message_type == proto &&
  266.     client_event->data.l[0]    == delwin) {
  267.       /* it's a WM_DELETE_WINDOW event */
  268.  
  269.       if (client_event->window == popW) {
  270.     FakeButtonPress(&bts[(nbts>1) ? nbts-1 : 0]);
  271.     rv = 1;
  272.       }
  273.     }
  274.   }
  275.  
  276.   if (rv==0 && (xev->type == KeyPress || xev->type == ButtonPress)) {
  277.     XBell(theDisp, 0);
  278.     rv = 1;            /* eat it */
  279.   }
  280.  
  281.   return rv;
  282. }
  283.  
  284.  
  285.  
  286. #define TR_MAXLN 10
  287.  
  288. /***************************************************/
  289. void TextRect(win, txt, x, y, w, h, fg)
  290.      Window  win;
  291.      char   *txt;
  292.      int     x,y,w,h;
  293.      u_long  fg;
  294. {
  295.   char *sp, *ep, *oldep, *start[TR_MAXLN];
  296.   int   i, inbreak, lineno, top, hardcr, maxln, len[TR_MAXLN];
  297.  
  298.   XSetForeground(theDisp, theGC, fg);
  299.   
  300.   sp = txt;  lineno = hardcr = 0;
  301.  
  302.   maxln = h / LINEHIGH;  
  303.   RANGE(maxln,0,TR_MAXLN);
  304.   while (*sp && lineno<maxln) {
  305.  
  306.     /* drop off any leading spaces (except on first line or after \n) */
  307.     if (sp!=txt && !hardcr) {
  308.       while(*sp==' ') sp++;
  309.     }
  310.  
  311.     hardcr = 0;   ep = sp;
  312.  
  313.     /* increment ep until we   A) get too wide, B) hit eos or
  314.        C) hit a '\n' character */
  315.  
  316.     /* NOTE: ep points to the character AFTER the end of the line */
  317.  
  318.     while (XTextWidth(mfinfo, sp, ep-sp) <= w && *ep && *ep!='\n') ep++;
  319.     if (*ep=='\n') { ep++;  hardcr=1; }   /* eat newline */
  320.  
  321.     /* if we got too wide, back off until we find a break position 
  322.        (last char before a space or a '/') */
  323.  
  324.     if (XTextWidth(mfinfo, sp, ep-sp) > w) {
  325.       oldep = ep;  inbreak = 0;
  326.       while (ep!=sp) {
  327.     ep--;
  328.     if ( inbreak && *ep!=' ') { ep++;  break; }
  329.     if (!inbreak && *ep==' ') inbreak = 1;
  330.     if (*ep=='/') { ep++; break; }
  331.       }
  332.       if (ep==sp) ep = oldep-1;  /* can't break this line.  oh well */
  333.     }
  334.  
  335.     start[lineno] = sp;  len[lineno] = ep-sp;
  336.     
  337.     /* make sure we don't print a trailing '\n' character! */
  338.     if (len[lineno] > 0) {
  339.       while (sp[len[lineno]-1] == '\n') len[lineno] = len[lineno] - 1;
  340.     }
  341.  
  342.     sp = ep;
  343.     lineno++;
  344.   }
  345.  
  346.   top = y + h/2 + (ASCENT-DESCENT)/2 - ((lineno-1)*LINEHIGH)/2;
  347.   if (top<y+ASCENT) top = y+ASCENT;
  348.  
  349.   for (i=0, y=top; i<lineno; i++, y+=LINEHIGH) {
  350.     if (start[i][0] != '\n')
  351.       XDrawString(theDisp, win, theGC, x, y, start[i], len[i]);
  352.   }
  353. }
  354.  
  355.  
  356. /***************************************************/
  357. static void createPUD()
  358. {
  359.   CARD32     data[2];
  360.   Atom       prop;
  361.  
  362.   popW = CreateWindow("xv confirm", "+0+0", PUWIDE, PUHIGH, infofg, infobg);
  363.   if (!popW) FatalError("can't create popup window!");
  364.  
  365.  
  366.   data[0] = (CARD32) XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
  367.   data[1] = (CARD32) time((long *)0);
  368.   prop = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE),
  369.  
  370.   XChangeProperty(theDisp, popW, prop, prop,
  371.           32, PropModeReplace, (unsigned char *) data, 2);
  372.  
  373.   XSelectInput(theDisp, popW, ExposureMask | ButtonPressMask | KeyPressMask
  374.            | VisibilityChangeMask);
  375.   XSetTransientForHint(theDisp, popW, mainW);
  376.  
  377.   bts = (BUTT *) NULL;
  378.   nbts = selected = firsttime = 0;
  379. }
  380.   
  381.  
  382. /***************************************************/
  383. static void drawPUD(x,y,w,h)
  384. int x,y,w,h;
  385. {
  386.   int  i,xt,yt;
  387.   XRectangle xr;
  388.  
  389.   xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  390.   XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
  391.  
  392.   XSetForeground(theDisp, theGC, infofg);
  393.   XSetBackground(theDisp, theGC, infobg);
  394.  
  395.   XCopyPlane(theDisp, iconPix, popW, theGC, 0,0, icon_width, icon_height,
  396.          10,10+(PUHIGH-30-BUTTH-icon_height)/2,1);
  397.  
  398.   xt = 10+icon_width+20;  yt = 10;
  399.   TextRect(popW, text, xt, yt, PUWIDE-10-xt, PUHIGH-10-BUTTH-20, infofg);
  400.  
  401.   for (i=0; i<nbts; i++) BTRedraw(&bts[i]);
  402.  
  403.   XSetClipMask(theDisp, theGC, None);
  404. }
  405.  
  406.  
  407. /***************************************************/
  408. static void clickPUD(x,y)
  409. int x,y;
  410. {
  411.   int i,j;
  412.   BUTT *bp;
  413.  
  414.   for (i=0; i<nbts; i++) {
  415.     bp = &bts[i];
  416.     if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
  417.   }
  418.  
  419.   if (i<nbts && BTTrack(bp)) {
  420.     popUp = 0;  selected = i;
  421.   }
  422. }
  423.  
  424.  
  425.